/*
 * Copyright 2015 Hannes Dorfmann.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hannesdorfmann.mosby3.mvp.lce;


import com.hannesdorfmann.mosby3.mvp.MvpFraction;
import com.hannesdorfmann.mosby3.mvp.MvpPresenter;
import com.hannesdorfmann.mosby3.mvp.ResourceTable;
import com.hannesdorfmann.mosby3.mvp.widget.CirleProgressImg;
import ohos.aafwk.content.Intent;
import ohos.agp.components.*;
import ohos.agp.window.dialog.ToastDialog;


/**
 * A {@link MvpLceFraction} that implements {@link MvpLceView} which gives you 3 options:
 * <ul>
 * <li>Display a loading view: A view with <b>ResourceTable.Id_loadingView</b> must be specified in your
 * inflated xml layout</li>
 * <li>Display a error view: A <b>TextView</b> with <b>ResourceTable.Id_errorView</b> must be declared in your
 * inflated xml layout</li>
 * <li>Display content view: A view with <b>ResourceTable.Id_contentView</b> must be specified in your
 * inflated
 * xml layout</li>
 * </ul>
 *
 * @param <CV> The type of the content view with the id = ResourceTable.Id_contentView. Can be any kind of
 * HarmonyOS Component widget like ListContainer, ScrollView or a simple layout like Stacklayout
 * etc. (everything that extends from ohos.agp.components.Component)
 * @param <M> The underlying data model that will be displayed with this view
 * @param <V> The View interface that must be implemented by this view. You can use {@link
 * MvpLceView}, but if you want to add more methods you have to provide your own view interface
 * that
 * extends from {@link MvpLceView}
 * @param <P> The type of the Presenter. Must extend from {@link MvpPresenter}
 * @author Hannes Dorfmann
 */
public abstract class MvpLceFraction<CV extends Component, M, V extends MvpLceView<M>, P extends MvpPresenter<V>>
    extends MvpFraction<V, P> implements MvpLceView<M> {

  protected CirleProgressImg loadingView;
  protected CV contentView;
  protected Text errorView;
  protected int loadingViewID,contentViewID,errorViewID;

  @Override
  protected void onComponentDetach() {
    super.onComponentDetach();
  }

  @Override
  protected void onStart(Intent intent) {
    super.onStart(intent);
  }

  protected abstract void initLceComponetID();

  @Override
  protected int getUIContent() {
    return 0;
  }

  protected void initCompoment(){
    initLceComponetID();
    loadingView = createLoadingView(mComponent);
    contentView = createContentView(mComponent);
    errorView = createErrorView(mComponent);

    if (loadingView == null) {
      throw new NullPointerException(
              "Loading view is null! Have you specified a loading view in your layout xml file?"
                      + " You have to give your loading View the id ResourceTable.Id_loadingView");
    }

    if (contentView == null) {
      throw new NullPointerException(
              "Content view is null! Have you specified a content view in your layout xml file?"
                      + " You have to give your content View the id ResourceTable.Id_contentView");
    }

    if (errorView == null) {
      throw new NullPointerException(
              "Error view is null! Have you specified a content view in your layout xml file?"
                      + " You have to give your error View the id ResourceTable.Id_errorView");
    }

    errorView.setClickedListener(new Component.ClickedListener() {
      @Override public void onClick(Component v) {
        onErrorViewClicked();
      }
    });
  }

  /**
   * Create the loading view. Default is {@code findComponentById(ResourceTable.Id_loadingView)}
   *
   * @param view The main view returned from {@link #onComponentAttached(LayoutScatter, ComponentContainer, Intent)}
   * @return the loading view
   */
  protected CirleProgressImg createLoadingView(Component view) {
    return (CirleProgressImg) view.findComponentById(loadingViewID/*ResourceTable.Id_loadingView*/);
  }

  /**
   * Create the content view. Default is {@code findComponentById(ResourceTable.Id_contentView)}
   *
   * @param view The main view returned from {@link #onComponentAttached(LayoutScatter, ComponentContainer, Intent)}}
   * @return the content view
   */
  protected CV createContentView(Component view) {
    return (CV) view.findComponentById(contentViewID/*ResourceTable.Id_contentView*/);
  }

  /**
   * Create the error view. Default is {@code findComponentById(ResourceTable.Id_errorView)}
   *
   * @param view The main view returned from {@link #onComponentAttached(LayoutScatter, ComponentContainer, Intent)}
   * @return the error view
   */
  protected Text createErrorView(Component view) {
    return (Text) view.findComponentById(errorViewID/*ResourceTable.Id_errorView*/);
  }

  @Override public void showLoading(boolean pullToRefresh) {
    if (!pullToRefresh) {
      animateLoadingViewIn();
    }

    // otherwise the pull to refresh widget will already display a loading animation
  }

  /**
   * Override this method if you want to provide your own animation for showing the loading view
   */
  protected void animateLoadingViewIn() {
    LceAnimator.showLoading(loadingView, contentView, errorView);
  }

  @Override public void showContent() {
    animateContentViewIn();
  }

  /**
   * Called to animate from loading view to content view
   */
  protected void animateContentViewIn() {
    LceAnimator.showContent(loadingView, contentView, errorView);
  }

  /**
   * Get the error message for a certain Exception that will be shown on {@link
   * #showError(Throwable, boolean)}
   */
  protected abstract String getErrorMessage(Throwable e, boolean pullToRefresh);

  /**
   * The default behaviour is to display a toast message as light error (i.e. pull-to-refresh
   * error).
   * Override this method if you want to display the light error in another way (like crouton).
   */
  protected void showLightError(String msg) {
    if (getContext() != null) {
      ToastDialog mToastDialog = new ToastDialog(getContext());
      mToastDialog.setText(msg);
      mToastDialog.setDuration(1000);
      mToastDialog.show();
    }
  }

  /**
   * Called if the error view has been clicked. To disable clicking on the errorView use
   * <code>errorView.setClickable(false)</code>
   */
  protected void onErrorViewClicked() {
    loadData(false);
  }

  @Override public void showError(Throwable e, boolean pullToRefresh) {
    String errorMsg = getErrorMessage(e, pullToRefresh);

    if (pullToRefresh) {
      showLightError(errorMsg);
    } else {
      errorView.setText(errorMsg);
      animateErrorViewIn();
    }
  }

  /**
   * Animates the error view in (instead of displaying content view / loading view)
   */
  protected void animateErrorViewIn() {
    LceAnimator.showErrorView(loadingView, contentView, errorView);
  }

  @Override public void onStop() {
    super.onStop();
    loadingView = null;
    contentView = null;
    errorView.setClickedListener(null);
    errorView = null;
  }
}

